package com.lizemin.proxy;

import cn.hutool.json.JSONUtil;
import com.lizemin.entity.User;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * @author lzm
 * @date 2025/5/16 21:14
 * @description
 */
@Slf4j
public class JdkProxy implements ProxyFactory {

    /**
     * 获取代理对象
     *
     * @param clazz 接口类
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T getProxy(Class<T> clazz) {
        if (!clazz.isInterface()) {
            throw new IllegalArgumentException("必须要是接口的class");
        }
        InvocationHandler handler = getInvocationHandler();
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, handler);
    }

    /**
     * 获取代理对象
     *
     * @param target 原始对象
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> T getProxy(Object target) {
        InvocationHandler handler = getInvocationHandler(target);
        Class<?> clazz = target.getClass();
        Class<?>[] interfaces = clazz.getInterfaces();
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{interfaces[0]}, handler);
    }

    /**
     * 获取方法拦截器
     * 有没有觉得这段代码和我们写的aop切面很类似？
     *
     * @return 方法拦截器
     */
    private InvocationHandler getInvocationHandler(Object target) {
        return (proxy, method, args) -> {
            log.info("方法的名称为：{}, 入参为：{}", method.getName(), Arrays.toString(args));
            Object result = method.invoke(target, args); //  调用目标方法, 这里之所以成立是因为实现类和接口类拥有完全相同的方法签名
            log.info("方法的返回值为：{}", JSONUtil.toJsonPrettyStr(result));
            return result;
        };
    }

    private static InvocationHandler getInvocationHandler() {
        return (proxy, method, args) -> {
            switch (method.getName()) {
                case "getUserById":
                    if (args[0] == null) {
                        throw new IllegalArgumentException("id不能为空！");
                    }
                    Integer id = (Integer) args[0];
                    log.info("开始从数据库中查询id为{}的用户信息！", id);
                    return getUser(id); // 返回方法执行后的结果
                case "getAllUsers":
                    log.info("开始从数据库中查询所有用户信息！");
                    return queryUsers();
                case "toString":
                    return "userMapper";
                case "hashCode":
                    return System.identityHashCode(proxy);
                case "equals":
                    return proxy == args[0];
            }
            return null;
        };
    }

    private static User getUser(Integer id) {
        User user = new User();
        user.setId(id);
        user.setName("csdn");
        user.setAge(20);
        return user;
    }

    private static ArrayList<User> queryUsers() {
        int id;
        ArrayList<User> users = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            id = i + 1;
            User user = new User();
            user.setId(id);
            user.setName("csdn—" + id);
            user.setAge(20 + i);
            users.add(user);
        }
        return users;
    }

}
